# Multi-stage Dockerfile for the {{ cookiecutter.mcp_app._artifact_title }} MCP App
# Installs the MCP server package, then creates a minimal runtime image with
# nginx, supervisord, the MCP server and the heartbeat.

# NOTE on BuildKit cache mounts: The cache mounts for apt, pip, and poetry persists downloaded
# packages across builds, making subsequent installs much faster. All builds on the same host
# share the same cache mounts (e.g., across multiple data apps), so packages downloaded once
# are reused everywhere. This dramatically speeds up builds and reduces network usage.

# ============================================================================
# Stage 1: Local MCP package (optional)
# ============================================================================
# Empty unless the build passes --build-context mcp-src=<path to a package checkout>,
# which replaces this stage. The poe docker tasks pass it when MCP_PACKAGE_PATH is set.
FROM scratch AS mcp-src

# ============================================================================
# Stage 2: Python Builder
# ============================================================================
FROM python:3.14-slim AS python-builder

# JFrog Artifactory credentials (optional)
ARG TS_PYPI_VIRTUAL_USER

WORKDIR /usr/src/app

# Install build dependencies and Poetry
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
    --mount=type=cache,target=/var/lib/apt,sharing=locked \
    apt-get update && apt-get install -y --no-install-recommends \
        gcc \
        g++ \
        make \
        libffi-dev \
    && pip install --upgrade pip \
    && pip install --upgrade setuptools poetry \
    && poetry config virtualenvs.create false

# Copy Poetry configuration files from root
COPY pyproject.toml poetry.lock* ./

# Install Python dependencies with TetraScience PyPI support
RUN --mount=type=cache,target=/root/.cache/pip \
    --mount=type=cache,target=/root/.cache/pypoetry \
    --mount=type=secret,id=TS_PYPI_VIRTUAL_TOKEN \
    if [ -n "${TS_PYPI_VIRTUAL_USER}" ]; then \
        POETRY_HTTP_BASIC_TS_PYPI_VIRTUAL_USERNAME=${TS_PYPI_VIRTUAL_USER} \
        POETRY_HTTP_BASIC_TS_PYPI_VIRTUAL_PASSWORD=$(cat /run/secrets/TS_PYPI_VIRTUAL_TOKEN) \
        poetry install --only main --no-root; \
    else \
        poetry install --only main --no-root; \
    fi

# Install the local MCP package checkout, if one was passed. It is installed after
# the locked dependencies, so it replaces any published version of the same package.
# The JFrog credentials go in a .netrc that is deleted in the same step.
RUN --mount=type=bind,from=mcp-src,target=/mcp-src,rw \
    --mount=type=cache,target=/root/.cache/pip \
    --mount=type=secret,id=TS_PYPI_VIRTUAL_TOKEN \
    if [ -f /mcp-src/pyproject.toml ]; then \
        if [ -n "${TS_PYPI_VIRTUAL_USER}" ]; then \
            printf 'machine tetrascience.jfrog.io login %s password %s\n' \
                "${TS_PYPI_VIRTUAL_USER}" "$(cat /run/secrets/TS_PYPI_VIRTUAL_TOKEN)" > /root/.netrc; \
        fi \
        && pip install \
            --extra-index-url https://tetrascience.jfrog.io/artifactory/api/pypi/ts-pypi-virtual/simple \
            /mcp-src \
        && rm -f /root/.netrc; \
    fi

# Cleanup to reduce image size (before copying to runtime stage)
RUN find /usr/local/lib/python3.14/site-packages -type d -name "tests" -exec rm -rf {} + 2>/dev/null || true \
    && find /usr/local/lib/python3.14/site-packages -type d -name "test" -exec rm -rf {} + 2>/dev/null || true \
    && find /usr/local/lib/python3.14/site-packages -name "*.so" -exec strip {} \; 2>/dev/null || true

# ============================================================================
# Stage 3: Runtime
# ============================================================================
FROM python:3.14-slim AS runtime

WORKDIR /app

# Set environment variables. CONNECT_VIA sets what the connect page shows: the direct
# setup (direct) or a note pointing users to the Tetra AI Gateway (gateway).
ENV PYTHONUNBUFFERED=1 \
    PYTHONDONTWRITEBYTECODE=1 \
    PORT=80 \
    CONNECT_VIA=direct

# Install supervisor and nginx
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
    --mount=type=cache,target=/var/lib/apt,sharing=locked \
    apt-get update && apt-get install -y --no-install-recommends \
        supervisor \
        nginx \
    && rm -rf /var/lib/apt/lists/*

# The MCP server runs as this unprivileged user (see conf/supervisord.conf).
RUN useradd --system --no-create-home --shell /usr/sbin/nologin mcp

# Copy Python dependencies from builder
COPY --from=python-builder /usr/local/lib/python3.14/site-packages /usr/local/lib/python3.14/site-packages
COPY --from=python-builder /usr/local/bin /usr/local/bin

# Copy the app package and install it (no deps — already present).
# This creates console script entry points (e.g. heartbeat) in /usr/local/bin.
COPY pyproject.toml README.md ./
COPY backend/ ./backend/
RUN pip install --no-deps .

# The connect page, served by nginx, with the app's manifest icon beside its title
COPY static/ ./static/
COPY images/icon.png ./static/icon.png

# Conditionally copy supervisord config based on deployment environment
COPY conf/ /tmp/conf/
COPY conf/nginx.conf /etc/nginx/nginx.conf

ARG DEPLOYMENT_ENVIRONMENT=production

RUN mkdir -p /etc/supervisor/conf.d \
    && if [ "$DEPLOYMENT_ENVIRONMENT" = "production" ]; then \
        cp /tmp/conf/supervisord.conf /etc/supervisor/conf.d/supervisord.conf; \
    elif [ "$DEPLOYMENT_ENVIRONMENT" = "local" ]; then \
        cp /tmp/conf/supervisord-local.conf /etc/supervisor/conf.d/supervisord.conf; \
    else \
        echo "Invalid DEPLOYMENT_ENVIRONMENT: $DEPLOYMENT_ENVIRONMENT"; \
        exit 1; \
    fi \
    && rm -rf /tmp/conf/ \
    && nginx -t

# Copy and set up entrypoint script
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh

# Expose Nginx
EXPOSE 80

# Run entrypoint script which displays startup info and starts supervisord
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
